package com.smsc.headend.task.engine.utils;

import com.emeter.energyip.amiinterface.*;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.module.asset.entity.Dcu;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.data.entity.MapDdsMdmWf;
import com.smsc.headend.module.data.entity.RdMeterReadsLp;
import com.smsc.headend.module.mdm.dds.entity.MapDdsMdmEventWf;
import com.smsc.headend.module.task.dto.TaskEventData;
import com.smsc.headend.task.engine.service.asset.AssetService;
import com.smsc.headend.task.engine.service.dds.MapDdsMdmEventWfService;
import com.smsc.headend.task.engine.service.dds.MapDdsMdmWfService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author qinbin
 * @date 2021/12/23 16:57
 */
@Component
@Slf4j
public class DdsXmlGenerateUtil {
    @Autowired
    private AssetService assetService;

    @Autowired
    private MapDdsMdmEventWfService mapDdsMdmEventWfService;

    @Autowired
    private MapDdsMdmWfService mapDdsMdmWfService;

    private final Map<String, MapDdsMdmWf> mapDdsMdmWfMap = new HashMap<>(100);

    private final Map<Long, MapDdsMdmEventWf> mapDdsMdmEventWfMap = new HashMap<>(100);

    private final static String DCU = "DC_";

    @PostConstruct
    public void initMappingRule() {
        // event 映射值
        List<MapDdsMdmEventWf> mapDdsMdmEventWfs = mapDdsMdmEventWfService.list();
        mapDdsMdmEventWfs.stream().forEach(mapDdsMdmEventWf -> {
            Long eventTypeId = mapDdsMdmEventWf.getEventType();
            mapDdsMdmEventWfMap.put(eventTypeId, mapDdsMdmEventWf);
        });

        // profile 映射值
        List<MapDdsMdmWf> mapDdsMdmWfs = mapDdsMdmWfService.getMapDdsMdmWfByFileType(3);
        mapDdsMdmWfs.stream().forEach(mapDdsMdmWf -> {
            Long subDataItemId = mapDdsMdmWf.getSubDataItemId();
            Long lpDataItemId = mapDdsMdmWf.getLpDataItemId();
            String key = new StringBuffer().append(lpDataItemId).append(":").append(subDataItemId).toString();
            mapDdsMdmWfMap.put(key, mapDdsMdmWf);
        });

    }

    public MeterReadsReplyMessageDocument getDocumentLp(List<RdMeterReadsLp> rdMeterReadsLps) {
        MeterReadsReplyMessageDocument document = MeterReadsReplyMessageDocument.Factory.newInstance();
        if (CollectionUtils.isEmpty(rdMeterReadsLps)) {
            return document;
        }
        MeterReadsReply meterReadsReply = document.addNewMeterReadsReplyMessage();
        MessageHeader messageHeader = meterReadsReply.addNewHeader();
        messageHeader.setVerb(MessageHeader.Verb.REPLY);
        messageHeader.setNoun("MeterReads");
        messageHeader.setRevision("1");
        messageHeader.setSource("UDIS");
        messageHeader.setDateTime(Calendar.getInstance());

        //分组:一个Meter对应一个MeterReading
        Map<Long, List<RdMeterReadsLp>> groupByMeterRdMeterReads = rdMeterReadsLps.stream().collect(Collectors.groupingBy(
                readsLp -> readsLp.getMeterId()));
        MeterReadings meterReadings = meterReadsReply.addNewPayload();
        meterReadings.setStartTime(Calendar.getInstance());
        meterReadings.setEndTime(Calendar.getInstance());

        for (Map.Entry<Long, List<RdMeterReadsLp>> lpMReadInfoEntry : groupByMeterRdMeterReads.entrySet()) {
            Long meterId = lpMReadInfoEntry.getKey();
            Meter meter = assetService.getMeterById(meterId);
            if (null == meter) {
                log.error("cannot find meter id={}", meterId);
                continue;
            }
            MeterReading meterReading = meterReadings.addNewMeterReading();
            MeterAsset meterAsset = meterReading.addNewMeter();
            meterAsset.setMRID(meter.getMfgSn());
            meterAsset.setServiceType("Electric");
            // 按DATA_ITEm+LP_DATA_ITEM分组分组,对应一个IntervalBlock
            Map<String, List<RdMeterReadsLp>> groupByDataItemRdMeterReads = lpMReadInfoEntry.getValue().stream().collect(Collectors.groupingBy(
                    readsLp -> readsLp.getLpDataItemId() + ":" + readsLp.getDataItemId()));

            for (Map.Entry<String, List<RdMeterReadsLp>> lpDReadInfoEntry : groupByDataItemRdMeterReads.entrySet()) {
                IntervalBlock intervalBlock = meterReading.addNewIntervalBlock();
                String key = lpDReadInfoEntry.getKey();
                MapDdsMdmWf mapDdsMdmWf = mapDdsMdmWfMap.get(key);
                String readIngTypeId = mapDdsMdmWf != null && !StringUtils.isEmpty(mapDdsMdmWf.getMdmDataItemId())
                        ? mapDdsMdmWf.getMdmDataItemId() : key.split(":")[1];
                intervalBlock.setReadingTypeId(readIngTypeId);
                lpDReadInfoEntry.getValue().forEach(rdMeterReadsLp -> {
                    IReading reading = intervalBlock.addNewIReading();
                    Date date = new Date(rdMeterReadsLp.getTv() * 1000);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(date);
                    reading.setEndTime(calendar);
                    reading.setValue(Double.parseDouble(rdMeterReadsLp.getValue()));
                    reading.setFlags(0L);
                });
            }

        }
        return document;
    }

    public MeterReadsReplyMessageDocument getDocumentEvent(List<TaskEventData> taskEventDatas) {
        MeterReadsReplyMessageDocument document = MeterReadsReplyMessageDocument.Factory.newInstance();
        if (CollectionUtils.isEmpty(taskEventDatas)) {
            return document;
        }
        MeterReadsReply meterReadsReply = document.addNewMeterReadsReplyMessage();
        MessageHeader messageHeader = meterReadsReply.addNewHeader();
        messageHeader.setVerb(MessageHeader.Verb.REPLY);
        messageHeader.setNoun("MeterData");
        messageHeader.setRevision("1");
        messageHeader.setSource("UDIS");
        messageHeader.setDateTime(Calendar.getInstance());

        MeterReadings meterReadings = meterReadsReply.addNewPayload();
        meterReadings.setStartTime(Calendar.getInstance());
        meterReadings.setEndTime(Calendar.getInstance());

        taskEventDatas.stream().forEach(taskEventData -> {
            Long deviceType = taskEventData.getDeviceType();
            String mfgSn = "";
            if (DeviceType.METER.getId().equals(deviceType)) {
                Meter meter = assetService.getMeterById(taskEventData.getDeviceId());
                mfgSn = null == meter ? "" : meter.getMfgSn();
            }
            if (DeviceType.DCU.getId().equals(deviceType)) {
                Dcu dcu = assetService.getDcuById(taskEventData.getDeviceId());
                mfgSn = null == dcu ? "" : DCU + dcu.getMfgSn();
            }
            if (!StringUtils.isEmpty(mfgSn)) {
                MeterReading meterReading = meterReadings.addNewMeterReading();
                MeterAsset meterAsset = meterReading.addNewMeter();
                meterAsset.setMRID(mfgSn);
                meterAsset.setServiceType("Electric");
                taskEventData.getRdEventMeter().forEach(rdEventMeter -> {
                            Event event = meterReading.addNewEvent();
                            String category = Category.getById(rdEventMeter.getLbDataItemId()).getName();
                            if (!StringUtils.isEmpty(category)) {
                                event.setCategory(Category.getById(rdEventMeter.getLbDataItemId()).getName());
                                event.setDescription(category + "; Even Code:" + rdEventMeter.getEventCode().toString());
                            } else {
                                event.setDescription("Even Code:" + rdEventMeter.getEventCode().toString());
                            }
                            MapDdsMdmEventWf mapDdsMdmEventWf = mapDdsMdmEventWfMap.get(rdEventMeter.getEventType().longValue());
                            String eventName = (mapDdsMdmEventWf != null && !StringUtils.isEmpty(mapDdsMdmEventWf.getEipEventDataItemName()))
                                    ? mapDdsMdmEventWf.getEipEventDataItemName() : rdEventMeter.getEventName();
                            event.setName(eventName);
                            Date date = new Date(rdEventMeter.getTv() * 1000);
                            Calendar calendar = Calendar.getInstance();
                            calendar.setTime(date);
                            event.setTimestamp(calendar);
                            event.setSource("UDIS");
                            event.setCollectionTime(Calendar.getInstance());
                        }
                );
            }
        });
        return document;
    }

    public MapDdsMdmWf getMapDdsMdmWf(Long lpDataItemId, Long subDataItemId) {
        return mapDdsMdmWfMap.get(lpDataItemId + ":" + subDataItemId);
    }

    public enum Category {
        UNKNOWN(0L, ""),
        DISCONNECTOR_CONTROL_LOG(1020070003L, "Disconnector Control Log"),
        STANDARD_EVENT_LOG(1020070004L, "Standard Event Log"),
        FRAUD_DETECTION_LOG(1020070005L, "Fraud Detection Log"),
        GLOBAL_RESET_EVENT_LOG(1020070007L, "Global Reset Event log"),
        GENERAL_DISPLAY_READOUT(1020070008L, "General display readout"),
        POWER_QUALITY_LOG(1020070012L, "Power Quality Log"),
        LOSS_ALL_VOLTAGE_PROFILE(1020070014L, "Loss All Voltage Profile"),
        PUSH_EVENT_CODE(1024000001L, "Push Event Code"),
        ;

        Category(Long id, String name) {
            this.id = id;
            this.name = name;
        }

        private Long id;
        private String name;


        public static Category getById(Long id) {
            return Stream.of(Category.values()).filter(category -> category.getId().equals(id)).findAny().orElse(UNKNOWN);
        }

        public String getName() {
            return name;
        }

        public Long getId() {
            return id;
        }
    }
}
